<?php

/**
 * This file is part of Webman AI.
 *
 * @author    walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link      http://www.workerman.net/
 */

namespace plugin\ai\app\handler;

use plugin\ai\app\model\AiApikey;
use plugin\ai\app\service\Azure;
use Throwable;

class Gpt3 extends Gpt
{
    /**
     * @var string 模型处理器名称
     */
    protected static $name = 'GPT3.5';

    /**
     * @var string 模型类型
     */
    protected static $type = 'gpt3';

    /**
     * @var bool 余额是否可见
     */
    protected static $balanceVisible = true;

    /**
     * @var string[] 支持的模型名称
     */
    public static $models = [
        'gpt-3.5',
        'gpt-3.5-turbo',
        'gpt-3.5-turbo-16k',
    ];

    /**
     * @var string[] 自定义配置
     */
    public static $defaultSettings = [
        'api' => [
            'name' => 'API',
            'type' => 'text',
            'value' => 'https://api.ailard.com',
            'desc' => 'API 地址',
        ],
        'allowNetwork' => [
            'name' => '允许联网',
            'type' => 'checkbox',
            'value' => false,
        ],
        'networkModel' => [
            'name' => '联网模型',
            'type' => 'text',
            'value' => 'ernie-bot',
            'desc' => '需要联网时使用的模型，例如ernie-bot',
        ],
        'regFreeCount' => [
            'name' => '注册赠送',
            'type' => 'number',
            'value' => 0,
        ],
        'dayFreeCount' => [
            'name' => '每日赠送',
            'type' => 'number',
            'value' => 0,
        ],
    ];

    /**
     * @var string 处理器
     */
    protected $driverClass = driver\Gpt::class;

    /**
     * @var string apikey
     */
    protected $apikey = '';

    /**
     * 对话
     * @param $data
     * @param $options
     * @return void
     */
    public function completions($data, $options)
    {
        $settings = $this->getRealSettings($data['model']);
        $this->driver = new $this->driverClass($settings);
        $options['complete'] = function ($result, $response) use ($options) {
            $this->checkApiKeyAvailable($result);
            if (isset($options['complete'])) {
                $options['complete']($result, $response);
            }
        };
        $this->driver->completions($data, $options);
    }

    /**
     * 从数据库中获取配置
     * @param $model
     * @return array
     */
    protected function getRealSettings(&$model): array
    {
        $azureSetting = Azure::getSetting();
        if (($azureSetting['enable']??false) && ($map = json_decode($azureSetting['map'], true)) && isset($map[$model]) && $azureSetting['api_host']) {
            $settings = [
                'api' => $azureSetting['api_host'],
                'isAzure' => true,
                'apikey' => $azureSetting['apikey1'] ?? $azureSetting['apikey2'] ?? ''
            ];
            $model = $map[$model];
        } else {
            $settings = parent::getSettings();
            [$this->apikey, $api] = static::getApiKeyFromDb($model);
            $settings['apikey'] = $this->apikey ?: ($settings['apikey'] ?? '');
            $settings['api'] = $api ?: $settings['api'];
        }
        return $settings;
    }


    /**
     * 从数据库中获取一条可用apikey
     * @param $model
     * @return array
     */
    public static function getApiKeyFromDb(&$model): array
    {
        try {
            $where = ['state'=> 0, strtolower(static::getClassName(true)) => 1];
            if (!$item = AiApikey::where($where)->orderBy('last_message_at')->orderBy('id')->first()) {
                return ['', ''];
            }
            $item->last_message_at = date('Y-m-d H:i:s');
            $item->message_count++;
            $item->save();
            return [$item->apikey ?: '', $item->api ?: ''];
        } catch (Throwable $exception) {}
        return ['', ''];
    }

    /**
     * 通过关键字检测apikey是否可用
     * @param $result
     * @return void
     */
    protected function checkApiKeyAvailable($result)
    {
        if (!isset($result['error']) || !isset($result['error']['message'])) {
            return;
        }
        $errorMessage = json_encode($result, JSON_UNESCAPED_UNICODE) ?? '';
        // 账号被禁用关键字
        $unavailableKeyWords = ['account_deactivated', 'billing_not_active', 'invalid_api_key', 'insufficient_quota', 'Incorrect API key', 'no_available_user_auth', 'used up your message credits for today'];
        $disabled = false;
        foreach($unavailableKeyWords as $word) {
            if (strpos($errorMessage, $word) !== false) {
                $disabled = true;
                break;
            }
        }
        // 查找apikey的记录
        $item = AiApikey::where('apikey', $this->apikey)->first();
        if ($item) {
            // 标记不可用
            if ($disabled) {
                $item->state = 1;
            }
            // 记录错误相关信息
            $item->last_error = $errorMessage;
            $item->error_count = $item->error_count + 1;
            $item->save();
        }
    }

}